/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.registry.security.vault.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Properties;
import org.apache.axis2.AxisFault;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.core.util.CryptoException;
import org.wso2.carbon.core.util.CryptoUtil;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.security.vault.CipherInitializer;
import org.wso2.carbon.registry.security.vault.internal.SecurityServiceHolder;
import sun.misc.BASE64Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
public class SecureVaultUtil {
private static Log log = LogFactory.getLog(SecureVaultUtil.class);
public static Properties loadProperties() {
Properties properties = new Properties();
String carbonHome = System.getProperty(SecureVaultConstants.CARBON_HOME);
String filePath = carbonHome + File.separator + SecureVaultConstants.REPOSITORY_DIR +
File.separator + SecureVaultConstants.CONF_DIR + File.separator +
SecureVaultConstants.SECURITY_DIR + File.separator +
SecureVaultConstants.SECRET_CONF;
File dataSourceFile = new File(filePath);
if (!dataSourceFile.exists()) {
return properties;
}
InputStream in = null;
try {
in = new FileInputStream(dataSourceFile);
properties.load(in);
} catch (IOException e) {
String msg = "Error loading properties from a file at :" + filePath;
log.warn(msg, e);
return properties;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {
}
}
}
return properties;
}
public static String encryptValue(String plainTextPass) throws AxisFault {
CipherInitializer ciperInitializer = CipherInitializer.getInstance();
byte[] plainTextPassByte = plainTextPass.getBytes();
try {
Cipher cipher = ciperInitializer.getEncryptionProvider();
if (cipher == null) {
if (cipher == null) {
log.error("Either Configuration properties can not be loaded or No secret"
+ " repositories have been configured please check PRODUCT_HOME/repository/conf/security "
+ " refer links related to configure WSO2 Secure vault");
handleException(log, "Failed to load security key store information ,"
+
"Configure secret-conf.properties properly by referring to https://docs.wso2.com/display/Carbon440/Encrypting+Passwords+with+Cipher+Tool",
null);
}
}
byte[] encryptedPassword = cipher.doFinal(plainTextPassByte);
BASE64Encoder encoder = new BASE64Encoder();
String encodedValue = encoder.encode(encryptedPassword);
return encodedValue;
} catch (IllegalBlockSizeException e) {
handleException(log, "Error encrypting password ", e);
} catch (BadPaddingException e) {
handleException(log, "Error encrypting password ", e);
}
return null;
}
private static void handleException(Log log, String message, Exception e) throws AxisFault {
if (e == null) {
AxisFault exception = new AxisFault(message);
log.error(message, exception);
throw exception;
} else {
message = message + " :: " + e.getMessage();
log.error(message, e);
throw new AxisFault(message, e);
}
}
public static void createRegistryResource(int tenantId) throws RegistryException {
try {
UserRegistry registry;
if (tenantId != -1234){
registry = SecurityServiceHolder.getInstance().getRegistryService().getConfigSystemRegistry(tenantId);
} else {
registry = SecurityServiceHolder.getInstance().getRegistryService().getConfigSystemRegistry();
}
// creating vault-specific storage repository (this happens only if
// not resource not existing)
if (!registry.resourceExists(SecureVaultConstants.ENCRYPTED_PROPERTY_STORAGE_PATH)) {
Collection secureVaultCollection = registry.newCollection();
registry.put(SecureVaultConstants.ENCRYPTED_PROPERTY_STORAGE_PATH, secureVaultCollection);
}
} catch (RegistryException e) {
throw new RegistryException("Error while intializing the registry");
}
}
/**
* Method to do the encryption operation.
*
* @param plainTextPass plain text value.
* @return encrypted value.
* @throws RegistryException Throws when an error occurs during encryption.
*/
public static String doEncrypt(String plainTextPass) throws CryptoException {
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
return cryptoUtil.encryptAndBase64Encode(plainTextPass.getBytes(Charset.forName("UTF-8")));
}
/**
* Method to decrypt a property, when key of the property is provided.
*
* @param key key of the property.
* @return decrypted property value.
* @throws RegistryException Throws when an error occurs during decryption.
*/
public static String getDecryptedPropertyValue(String key) throws RegistryException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
UserRegistry registry = SecurityServiceHolder.getInstance().getRegistryService()
.getConfigSystemRegistry(tenantId);
if (registry.resourceExists(SecureVaultConstants.ENCRYPTED_PROPERTY_STORAGE_PATH)) {
Resource registryResource = registry.get(SecureVaultConstants.ENCRYPTED_PROPERTY_STORAGE_PATH);
String propertyValue = registryResource.getProperty(key);
if (propertyValue != null) {
try {
return doDecrypt(propertyValue);
} catch (CryptoException | UnsupportedEncodingException e) {
throw new RegistryException("Error while decrypting the property value", e);
}
} else {
throw new RegistryException("Property does not exist with key \"" + key + "\" at path " +
SecureVaultConstants.ENCRYPTED_PROPERTY_CONFIG_REGISTRY_PATH);
}
} else {
throw new RegistryException("Collection does not exist at path "
+ SecureVaultConstants.ENCRYPTED_PROPERTY_CONFIG_REGISTRY_PATH);
}
}
/**
* Method to decrypt a property, when encrypted value is provided.
*
* @param encryptedValue encrypted property value.
* @return decrypted value.
* @throws CryptoException Throws when an error occurs during decryption.
* @throws UnsupportedEncodingException Throws when an error occurs during byte array to string conversion.
*/
public static String doDecrypt(String encryptedValue) throws CryptoException, UnsupportedEncodingException {
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
byte[] decryptedBytes = cryptoUtil.base64DecodeAndDecrypt(encryptedValue);
return new String(decryptedBytes, "UTF-8");
}
}